/**
      不可用于商业用于，教育例外
      通过解析安卓端发来的文本，执行不同的动作
      目前已经可以控制步进电机，已及引脚的write和read
      不可将本文件的代码或衍生代码，二进制文件等用于商业用途，教育除外
*/


#include <ESP8266WiFi.h>
#include <SPI.h>
#include <LinkedList.h>

//退出条件，必须以  + 结尾
class Ruler {
  private:
    String _ruler;
    Ruler *_next;
    int _time = -1; //运行次数
    int pin = -1; //引脚
    int result = -1; //电平高低
    int ar = false;//是否为analogRead

  public:
    Ruler(String ruler) {
      _ruler = ruler;
      execArray(ruler);
      /*
        Serial.println(_ruler);
        Serial.println(time);
        Serial.println(pin);
        Serial.println(result);
        Serial.println(ar);*/
    }


    void execArray(String command) {
      int index = command.indexOf("+");
      if (index >= 0) {
        system_soft_wdt_feed();
        String rl = command.substring(0, index);
        exec(rl);
        String _end = command.substring(index + 1, command.length());
        Ruler ruler(_end);
        _next = &ruler;
        _next->_time = _time - 1;
      } else {
        Serial.println("Ruler End.");
        return;
      }
    }
    void exec(String cmd) {
      String m = "Ruler : ";
      Serial.println(m + cmd);
      if (cmd.startsWith("G")) {
        pin = cmd.substring(1, cmd.indexOf("=")).toInt();
        result = cmd.substring(cmd.indexOf("=") + 1, cmd.length()).toInt();
        ar = false;
      } else if (cmd.startsWith("R")) {
        pin = cmd.substring(1, cmd.indexOf("=")).toInt();
        result = cmd.substring(cmd.indexOf("=") + 1, cmd.length()).toInt();
        ar = true;
      } else {
        _time = cmd.toInt();
      }
    }

    bool next() {
      system_soft_wdt_feed();
      bool back = true;
      if (_time == -1 && pin == -1) {
        Serial.println("Ruler Error!!!!!!!!");
        return false;
      }
      if (_time != -1) {
        if ( (--_time) >= 0) {
          back =  true;
        } else {
          return false;
        }
      }
      else {
        if (pin != -1) {
          if (ar = false) {
            if ( digitalRead(pin) != result) {
              back =  _next->next();
            } else return false;
          }
        } else {
          if ( analogRead(pin) != result) {
            back =  _next->next();
          } else return false;
        }
      }
      return back;
    }
};





class LED {
  public :
    int CODE0 = 0xFC;
    int CODE1 = 0XC0;
    int CODE = -1;
    LED *_next;
  public:
    LED(int ruler) {
      CODE = ruler;
    }
};



//主机（上位机） 信息
const char* ssid = "Ngx";
const char* password = "00000000";
const int port = 54322;

//版本号
const char* vs = "1.1";
const char* module = "drive1";




//最后一次操作的id
String id;

//执行次数
long  t = 0;

WiFiClient client;
String temp0;
String temp1;
String temp2;
String temp3;
String temp4;
String temp5;
String temp6;
//
String temp7;
void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println(".");
  }
  Serial.println("");
  Serial.println("Connected.");
  Connect();
}

void Connect() {
  String vip = WiFi.gatewayIP().toString();
  if (!client.connect(vip, port)) {
    return;
  }
  client.print(hello());
  client.flush();
}

String hi() {
  String message = "{\"version\":\"";
  message += vs;
  message += "\", \"name\":\"";
  message += module;
  message +=  "\",\"id\":\"";
  message += id;
  message += "\"}\n\0";
  return message;
}

String hello() {
  String message = "\n";
  message += "Hello From ESP8266 \n";
  message += "By Celivad\n";
  message += "By Bitbits\n";
  message += "Version 1.0.1\n";
  message += "[Ip:";
  message += WiFi.localIP().toString();
  message += ",Host:";
  message +=  WiFi.gatewayIP().toString();
  message +=  "]\0";
  return message;
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    setup();
    delay(500);
  } else {
    if (!client.connected()) {
      Connect();
      delay(1000);
      return;
    }
    while (client.available()) {
      String line = client.readStringUntil('\r');
      exec(line);
    }
  }
}


void exec(String command) {
  temp0 = command;
  int index;
  temp1 = "";
  do {
    index = temp0.indexOf("&");
    if (index != -1) {
      temp1 = temp0.substring(0, index);
      temp0 = temp0.substring(index + 1, temp0.length());
    } else {
      if (temp0.length() > 0) {
        temp1 = temp0;
      }
    }
    execCommand(temp1);
    temp1 = "";
  } while (index >= 0);
  system_soft_wdt_restart();
  String back = "{\"result\":\"true\",\"id\":\"";
  back += id;
  back += "\"";
  back += ",\"time\":";
  back.concat(t);
  client.print(back + "}\0");
  client.flush();
  t = 0;
}



void execArray(String command) {
  temp2 = command;
  int index;
  temp3 = "";
  do {
    system_soft_wdt_feed();
    index = temp2.indexOf(";");
    if (index != -1) {
      temp3 = temp2.substring(0, index);
      temp2 = temp2.substring(index + 1, temp2.length());
    } else {
      if (temp2.length() > 0) {
        temp3 = temp2;
      }
    }
    execCommand(temp3);
    temp3 = "";
    t++;
  } while (index >= 0);
}


//0 INOUT 1 OUTPUT
//0 低电平 1高电平

void execCommand(String command) {
  if (command.startsWith("[")) {
    int lf = command.indexOf("(");
    int rf = command.indexOf(")");
    temp4 = command.substring(lf + 1, rf);

    int l = command.indexOf("[");
    int r = command.indexOf("]");
    String cmd = command.substring(l + 1, r);
    Ruler ruler(temp4);
    while (ruler.next()) {
      execArray(cmd);
    }
    return;
  }
  int index = command.indexOf("=");
  String tag = command.substring(0, index);
  String result = command.substring(index + 1, command.length());
  int res = 0;



  if (tag == "id") {
    id = result;
    return;
  }

  if (tag == "D") {
    delay(result.toInt());
    return;
  } else if (tag == "d") {
    delayMicroseconds(result.toInt());
    return;
  }

  if (tag.startsWith("SPI.")) {
    SPI_(command);
    return;
  }

  if (tag == "hi") {
    Serial.print(hi());
    client.print(hi());
    client.flush();
    return;
  }
  if (tag == "GetAll") {
    String all = readAll();
    client.print(all);
    client.flush();
    return;
  }
  if (tag == "ReadAll") {
    String all = readAndlog();
    client.print(all);
    client.flush();
    return;
  }

  if (tag == "Reset") {
    String back = "{\"result\":\"true\",\"id\":\"";
    back += id;
    back += "\"";
    back += ",\"time\":";
    back.concat(t);
    client.print(back + "}\0");
    client.flush();
    delay(1000);
    ESP.reset();
    return;
  }

  if (tag == "Restart") {
    String back = "{\"result\":\"true\",\"id\":\"";
    back += id;
    back += "\"";
    back += ",\"time\":";
    back.concat(t);
    client.print(back + "}\0");
    client.flush();
    delay(1000);
    ESP.restart();
    return;
  }
  if (result == "INPUT" || result == "0" || result == "LOW") {
    res = 0;
  } else if (result == "OUTPUT" || result == "1" || result == "HIGH") {
    res = 1;
  } else {
    res = result.toInt();
  }

  int pin = tag.substring(1, tag.length()).toInt();
  if (tag.startsWith("S")) {
    digitalWrite(pin, res);
  } else if (tag.startsWith("M")) {
    pinMode(pin, res);
  } else if (tag.startsWith("P")) {
    pwm(pin, res);
  } else if (tag.startsWith("A")) {
    analogWrite(pin, res);
  }
}

LinkedList<int> led_ = LinkedList<int>();
void SPI_(String command) {
  /*
    Serial.println(MSBFIRST);
    Serial.println(SPI_CLOCK_DIV2);
  */
  int index = command.indexOf("=");
  String tag = command.substring(0, index);
  String result = command.substring(index + 1, command.length());
  if (tag == "SPI.begin") {
    SPI.begin();
    return;
  }
  if (tag == "SPI.setBitOrder") {
    SPI.setBitOrder(MSBFIRST);
    return;
  }
  if (tag == "SPI.setClockDivider") {
    SPI.setClockDivider(SPI_CLOCK_DIV2);
    return;
  }
  if (tag == "SPI.transfer") {
//    SPI.transfer(result.toInt());
    led_.add(result.toInt());
    return;
  }
  if (tag == "SPI.show") {
    for (int i = 0 ; i < led_.size(); i++) {
      SPI.transfer(led_.get(i));
    }
    led_.clear();
    return;
  }
}



void pwm(int pin, int hz) {
  for (int i = 0; i < hz; i++) {
    digitalWrite(pin, HIGH);
    delayMicroseconds(10);
    digitalWrite(pin, LOW);
    delayMicroseconds(10);
  }
}

String readAndlog() {
  String result = " {";
  int pins[] = {D0, D1, D2, D3, D4, D5, D6, D7, D8, LED_BUILTIN};
  String spin[] = {"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "LED_BUILTIN"};
  int length = sizeof(pins) / sizeof(pins[0]);
  for (int a = 0; a < length; a++) {
    result += String("\"") + spin[a] + String("\":") + analogRead(pins[a]);
    if (a != length - 1) {
      result += String(",");
    }
  }
  result += ",\"id\":\"";
  result += id;
  result += "\"}\0";
  return result;
}

String readAll() {
  String result = " {";
  int pins[] = {D0, D1, D2, D3, D4, D5, D6, D7, D8, LED_BUILTIN};
  String spin[] = {"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "LED_BUILTIN"};
  int length = sizeof(pins) / sizeof(pins[0]);
  for (int a = 0; a < length; a++) {
    result += String("\"") + spin[a] + String("\":") + digitalRead(pins[a]);
    if (a != length - 1) {
      result += String(",");
    }
  }
  result += ",\"id\":\"";
  result += id;
  result += "\"}\0";
  return result;
}

void sendError(String what) {
  client.print(what);
  client.flush();
}